home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
AmigActive 22
/
AACD 22.iso
/
AACD
/
Resources
/
General
/
ProNET
/
src
/
device
/
pronet.device.s
Wrap
Text File
|
1999-05-28
|
30KB
|
1,305 lines
*
* pronet.device
*
VERSION equ 38
REVISION equ 1
******* pronet.device/--Overview-- ******************************************
*
* IMPORTANT: Everything in here is subject to change. This is a "private"
* device, but I've documented it nevertheless. Don't expect your programs
* to run with future versions of the device!
*
* >> GENERAL INFORMATION <<
*
* The device is able to handle several Units, which are defined in the
* `devs:pronet/.config' file. Each Unit corresponds to a certain driver
* and interface. The Units are subdivided into Ports, which are channels
* between two sides of one Unit. This way two application systems may work
* through the same connection without interfering each other.
*
* pronet.device is *not* a SANA-II compliant networking device, and it is not
* compatible to any other exec device, because it's got some very strange
* behaviour regarding incoming data. Sometimes it is useful, sometimes it is
* not, but I will not change this anyway: CMD_READ is not supported, instead
* of that, when opening the device, you specify a MsgPort to which all
* incoming data will be sent automatically, if you want it or not!
*
* pronet.device v37 is incompatible to ProNET applications written
* earlier, see below. I'm sorry for that, but I've not heard from people
* using this device anyway ;-)
*
* >> ERROR CODES <<
*
* pronet.device v37 can return one of the following error codes after
* OpenDevice():
*
* PNDERR_PORTEXISTS
* You've tried to open up a Port which is already in use.
*
* PNDERR_DRIVERTROUBLE
* The driver of the Unit you requested can not be started.
* You can request a more detailed error message by setting the
* according bit in OpenDevice()/Flags. pnr_Data must then point to
* a buffer provided by you. The string will not exceed 63 characters
* plus the terminating zero. If no error occurs, the buffer will
* not be changed!
*
* PNDERR_UNIT_NOT_DEFINED
* The Unit you requested is missing a definition in the config file.
*
* >> CHANGES SINCE V3 <<
*
* v37: Write doesn't support two chunks anymore, Write can fail
* with PNDERR_DESTINATION_GONE now, no more #?ConfigString() in order
* to keep the configuration file tidy. Structure of received data
* has changed. PNB_ERRORSTRING.
*
* >> WRITING DRIVERS <<
*
* You find information on this subject in the other autodoc file supplied
* with the ProNET distribution.
*
*****************************************************************************
*
*
include "A:OSmacros.i"
include "exec/exec.i"
include "dos/dosextens.i"
include "devices/timer.i"
include "P:include/devices/pronet.i"
include "exec_lib.i"
include "dos_lib.i"
moveq #-1,d0
rts
STRUCTURE MyDev,LIB_SIZE *** Device Base
APTR pnd_SegList ;Segment List
APTR pnd_UnitList ;List of all Units
STRUCT pnd_Semaphore,SS_SIZE ;for Single-Threading DevOpen()
LABEL pnd_SizeOf
STRUCTURE MyUnit,0 *** Unit Structure
APTR pndu_Next
ULONG pndu_Number
UWORD pndu_OpenCnt
APTR pndu_ProcName
APTR pndu_ProcessID
APTR pndu_SysBase
APTR pndu_DOSBase
UWORD pndu_RC
APTR pndu_MsgPort
APTR pndu_MsgBackPort
APTR pndu_PortList
APTR pndu_ConfigString
STRUCT pndu_DriverName,30
BPTR pndu_DriverSeg
STRUCT pndu_DriverData,pndd_Size
STRUCT pndu_PendingReads,12
STRUCT pndu_PendingWrites,12
LABEL pndu_SizeOf
STRUCTURE PortMember,0 *** One Port of a Unit
APTR pndp_Next
UWORD pndp_Number
ULONG pndp_MsgPort
LABEL pndp_SizeOf
PNDCMD_ADDPORT equ CMD_NONSTD+4
PNDCMD_REMPORT equ CMD_NONSTD+5
LibResident dc.w RTC_MATCHWORD
dc.l LibResident
dc.l EndResident
dc.b RTF_AUTOINIT
dc.b VERSION
dc.b NT_DEVICE
dc.b 0
dc.l DevName
dc.l IDString
dc.l LibInitData
DevName dc.b "pronet.device",0
dc.b "$VER: "
IDString dc.b "pronet.device "
dc.b (VERSION/10)+48,(VERSION-((VERSION/10)*10))+48,".",REVISION+48
dc.b " (28.5.99)",13,10,0
even
LibInitData dc.l pnd_SizeOf
dc.l FuncTab
dc.l DataTab
dc.l Init
FuncTab dc.l Open
dc.l Close
dc.l Expunge
dc.l ExtFunc
dc.l BeginIO
dc.l AbortIO
dc.l -1
DataTab INITBYTE LN_TYPE,NT_DEVICE
INITLONG LN_NAME,DevName
INITBYTE LIB_FLAGS,LIBF_SUMUSED!LIBF_CHANGED
INITWORD LIB_VERSION,VERSION
INITWORD LIB_REVISION,REVISION
INITLONG LIB_IDSTRING,IDString
dc.w 0
OurBase dc.l 0
*****i* pronet.device/DevInit ***********************************************
*
* NAME
* DevInit -- Device is initialized after being loaded into memory.
*
* FUNCTION
* This function used to perform a keyfile check. Not any longer.
*
*****************************************************************************
*
* d0 is *OurBase, a0 is *SegList
* must return NULL for error or *SegList for OK.
Init movem.l d1-d7/a0-a6,-(sp)
move.l d0,a5
move.l a5,OurBase
move.l a0,pnd_SegList(a5)
move.l a5,a4 ;Device startupped correctly
* We need this SignalSemaphore to artificially single-thread our Open
* routine, because we break the exec single-threading by WaitIO.
lea pnd_Semaphore+SS_SIZE(a5),a0
moveq #SS_SIZE/2-1,d0
.clrsema clr.w -(a0)
dbra d0,.clrsema
LIBCALL InitSemaphore
move.l a4,d0
movem.l (sp)+,d1-d7/a0-a6
rts
dc.l $0BADD00D
******* pronet.device/OpenDevice ********************************************
*
* NAME
* OpenDevice -- Open up a new port of a certain ProNET Unit.
*
* SYNOPSIS
* error = OpenDevice("pronet.device", unit, ioRequest, flags);
* D0 A0 D0 A1 D1
*
* BYTE OpenDevice(STRPTR, ULONG, struct PNRequest*, ULONG);
*
* FUNCTION
* This is an exec.library call.
*
* Hey, what do you think it does?!??
*
* INPUTS
* unit - This number must be defined in the `DEVS:ProNET/.config' file,
* otherwise OpenDevice() will return PNDERR_UNIT_NOT_DEFINED.
* ioRequest - A pointer to an initialized (see below) PNRequest block.
* flags - As described in the overview page, you have the option
* to get extensive error messages when setting a bit here.
* The bit is defined as PNB_ERRORSTRING (the PNF_ definition also
* exists).
*
* Two components of the PNRequest must be initialized before calling
* OpenDevice():
*
* pnr_MsgPort - pointer to a MsgPort where incoming data is sent to.
* pnr_NetSourcePort - The port number you want to open.
*
* RESULT
* error - zero if everything went o.k., otherwise an error code
* as defined in exec/errors.h or devices/pronet.h.
*
* NOTES
* The *one and only* valid port numbers are 0x0001 to 0x7fff. If you
* want a special number above 0x7fff reserved for your application,
* please contact me!
*
* If you don't have any special preferences for your port number,
* you can use PNP_NEXTFREE to let pronet.device assign you the next
* free one (it will be put into pnr_NetSourcePort then).
*
*****************************************************************************
*
Open movem.l a2-a6/d2-d7,-(sp)
; Any AllocMem could call our Expunge vector, so prevent that by faking
; an opener!
addq.w #1,LIB_OPENCNT(a6)
move.l d0,d6 ;Unit
move.l a1,a2 ;IORequest
move.l a6,a5 ;DevBase
move.l d1,pnr_Length(a2)
move.l 4.w,a6
* We do this so that InitUnit can modify OurBase->pnd_UnitList without
* danger. Forbid/Permit sucks...
lea pnd_Semaphore(a5),a0
LIBCALL ObtainSemaphore
move.b #IOERR_OPENFAIL,IO_ERROR(a2)
* Does the required Unit already exist?
lea pnd_UnitList(a5),a3
.searchunit move.l (a3),d0
beq.s .newunit
move.l d0,a3
cmp.l pndu_Number(a3),d6
bne.s .searchunit
bra.s .unitok
* No! So create a Unit!
.newunit bsr InitUnit
tst.l d0
beq.s .ende
move.l d0,a3
* Yes! Add new port now! Unit-Structure in a3
.unitok move.w #PNDCMD_ADDPORT,IO_COMMAND(a2)
move.l a2,a1
move.l pndu_MsgPort(a3),a0
LIBCALL PutMsg
move.l a2,a1
LIBCALL WaitIO
tst.b d0
bne.s .ende
move.l a3,IO_UNIT(a2)
addq.w #1,pndu_OpenCnt(a3)
* Device successfully opened.
bclr #LIBB_DELEXP,LIB_FLAGS(a5)
addq.w #1,LIB_OPENCNT(a5)
move.b #NT_REPLYMSG,LN_TYPE(a2)
clr.b IO_ERROR(a2)
.ende lea pnd_Semaphore(a5),a0
LIBCALL ReleaseSemaphore
subq.w #1,LIB_OPENCNT(a5)
move.b IO_ERROR(a2),d0
beq.s .0
move.l #-1,IO_DEVICE(a2)
move.l #-1,IO_UNIT(a2)
.0 movem.l (sp)+,a2-a6/d2-d7
rts
; -- Create new Unit
InitUnit ; a5 *DevBase
; a2 *IORequest
; d6 Unit
; RETURNS d0 *Unit-Structure or NULL
moveq #0,d7
move.l 4.w,a6
lea dosname(pc),a1
moveq #0,d0
LIBCALL OpenLibrary
move.l d0,d5
beq .nodos
move.l #pndu_SizeOf,d0
move.l #MEMF_PUBLIC!MEMF_CLEAR,d1
LIBCALL AllocMem
tst.l d0
beq .nomem1
move.l d0,a3
move.l d6,pndu_Number(a3)
moveq #32,d0
move.l #MEMF_PUBLIC,d1
LIBCALL AllocMem
tst.l d0
beq.s .nomem2
move.l d0,a4
move.l a4,pndu_ProcName(a3)
move.l d6,-(sp)
pea FormatString(pc)
move.l a4,-(sp)
bsr _mysprintf
add.w #12,sp
* First, create Unit process
move.l d5,a6
move.l a4,d1
moveq #0,d2
move.l #ProcessCode-4,d3
lsr.l #2,d3
move.l #4096,d4
LIBCALL CreateProc
move.l d0,pndu_ProcessID(a3)
beq.s .noprocess
* Notify process about Unit number, this is the only message we send
* to the Process MsgPort, all the others from BeginIO go to a new MsgPort
* that is created while the Process' initialization.
move.l 4.w,a6
move.l a2,a1
move.l a3,IO_UNIT(a1)
clr.b IO_FLAGS(a1)
move.l d0,a0
LIBCALL PutMsg
* Wait for Process to finish initialization
move.l a2,a1
LIBCALL WaitIO
tst.b d0
bne.s .noprocess
* Now add this Unit-Structure to our internal List!!
lea pnd_UnitList(a5),a0
move.l (a0),(a3)
move.l a3,(a0)
move.l a3,d7
bra.s .nomem1
.noprocess move.l 4.w,a6
move.l a4,a1
moveq #32,d0
LIBCALL FreeMem
.nomem2 move.l a3,a1
move.l #pndu_SizeOf,d0
LIBCALL FreeMem
.nomem1 move.l d5,a1
LIBCALL CloseLibrary
.nodos move.l d7,d0
rts
******* pronet.device/CloseDevice *******************************************
*
* NAME
* CloseDevice -- Close a port of a certain ProNET Unit.
*
* SYNOPSIS
* CloseDevice(PNRequest);
* A1
*
* FUNCTION
* This is an exec.library call.
*
* This function terminates access to the corresponding ProNET Unit.
* Since the Unit is not shut down automatically, even if you were
* the last user of it, a RemDevice() would be the right thing to
* do after closing pronet.device.
*
* INPUTS
* PNRequest - A pointer to a previously opened ProNET IO Request.
*
* EXAMPLE
* This code can force a specified device to try and expunge.
* Of course, if the device is in use nothing will happen:
*
* void FlushDevice(name)
* char *name;
* {
* struct Device *result;
*
* Forbid();
* if(result=(struct Device *)FindName(&SysBase->DeviceList,name))
* RemDevice(result);
* Permit();
* }
*
* SEE ALSO
* exec.library/CloseDevice(), exec.library/RemDevice()
*
*****************************************************************************
*
*
Close movem.l a2/a5,-(sp)
move.l a1,a2
move.l a6,a5
move.l 4.w,a6
move.l IO_UNIT(a1),a0
subq.w #1,pndu_OpenCnt(a0)
move.l pndu_MsgPort(a0),a0
move.w #PNDCMD_REMPORT,IO_COMMAND(a1)
LIBCALL PutMsg
move.l a2,a1
LIBCALL WaitIO
move.l a2,a1
move.l a5,a6
move.l #-1,IO_DEVICE(a1)
move.l #-1,IO_UNIT(a1)
subq.w #1,LIB_OPENCNT(a6)
moveq #0,d0
movem.l (sp)+,a2/a5
rts
; -- This routine was kept free by Commodore for about 10 years now ;)
ExtFunc moveq #0,d0
rts
*****i* pronet.device/BeginIO ***********************************************
*
* NAME
* BeginIO -- Execute a device command.
*
* FUNCTION
* This is an exec.library call.
*
* We don't support any QUICK operations, so this bit is cleared
* in any case.
*
*****************************************************************************
*
*
BeginIO move.l a6,-(sp)
move.b #NT_MESSAGE,LN_TYPE(a1)
bclr #IOB_QUICK,IO_FLAGS(a1)
clr.b IO_ERROR(a1)
move.l IO_UNIT(a1),a0
move.l pndu_MsgPort(a0),a0
move.l 4.w,a6
LIBCALL PutMsg
move.l (sp)+,a6
rts
*****i* pronet.device/AbortIO ***********************************************
*
* NAME
* AbortIO -- Abort a currently queued IO request.
*
* FUNCTION
* This is an exec.library call.
*
* Sorry folks, we don't support AbortIO.
*
*****************************************************************************
*
*
AbortIO moveq #0,d0 ;Gar nix geht ab hier.
rts
*****i* pronet.device/Expunge ***********************************************
*
* NAME
* Expunge -- Prepare device removal.
*
* FUNCTION
* This is an exec.library call.
*
* We return *SegList if the device can be deallocated or NULL if we
* have still openers.
*
* Even if we have openers, we try to get rid of all unused Units.
*
*****************************************************************************
*
*
Expunge movem.l d2-d7/a2-a6,-(sp)
move.l a6,a5
move.l 4.w,a6
sub.l a1,a1
LIBCALL FindTask
move.l d0,expungetask
moveq #-1,d0
LIBCALL AllocSignal
move.b d0,expungesignal
move.b d0,d7
bmi.s .delexp
lea pnd_UnitList(a5),a3
.browseunits move.l a3,a4 ;a4=lastpt
move.l (a3),d0
.browseunitse beq.s .nomoreunits
move.l d0,a3 ;a3=current
tst.w pndu_OpenCnt(a3)
bne.s .browseunits
move.l pndu_ProcessID(a3),a1
lea -pr_MsgPort(a1),a1
move.l #SIGBREAKF_CTRL_C,d0
LIBCALL Signal
moveq #0,d0
bset d7,d0
LIBCALL Wait
move.l pndu_ProcName(a3),a1
moveq #32,d0
LIBCALL FreeMem
move.l (a3),d2
move.l d2,(a4)
move.l a3,a1
move.l #pndu_SizeOf,d0
LIBCALL FreeMem
move.l d2,d0
bra.s .browseunitse
.nomoreunits move.b d7,d0
LIBCALL FreeSignal
tst.w LIB_OPENCNT(a5)
beq.s .expunge
.delexp moveq #0,d0
bset #LIBB_DELEXP,LIB_FLAGS(a6)
bra.s .ende
.expunge move.l pnd_SegList(a5),d2 ;The whole Device is not used,
move.l a5,a1 ;so quit everything!
LIBCALL Remove
move.l a5,a1
moveq #0,d0
move.w LIB_NEGSIZE(a5),d0
sub.l d0,a1
add.w LIB_POSSIZE(a5),d0
LIBCALL FreeMem
move.l d2,d0
.ende movem.l (sp)+,d2-d7/a2-a6
rts
expungetask dc.l 0
expungesignal dc.b 0,0
** -----------------------------------------------------------------------
**
**
**
**
**
** DeviceUnit Process Code
**
**
**
**
**
** -----------------------------------------------------------------------
cnop 0,4
* First we will receive the first requestor's IORequest as a startup
* message. It contains the Unit structure in IO_UNIT. We must init
* and return with an error code in IO_ERROR.
ProcessCode move.l 4.w,a6
sub.l a1,a1
LIBCALL FindTask
move.l d0,a2
lea pr_MsgPort(a2),a2
move.l a2,a0
LIBCALL WaitPort
move.l a2,a0
LIBCALL GetMsg
move.l d0,a3
move.b #IOERR_OPENFAIL,IO_ERROR(a3) ;[a3] Startupmsg
move.l IO_UNIT(a3),a5
st pndu_RC(a5)
* Get Library Bases. We do *not* do it once in DevInit, but for every
* new process, since all this shit could (and will) change with PowerPC.
move.l a6,pndu_SysBase(a5)
lea dosname(pc),a1
moveq #0,d0
LIBCALL OpenLibrary
move.l d0,pndu_DOSBase(a5)
beq .nodos
lea pndu_PendingReads(a5),a1
NEWLIST a1
lea pndu_PendingWrites(a5),a1
NEWLIST a1
* Get port for messages replied from the applications
bsr CreatePort
move.l d0,pndu_MsgBackPort(a5)
beq .noport
* Get new port for all the messages arriving from BeginIO()
bsr CreatePort
move.l d0,pndu_MsgPort(a5)
beq .noport2
* Get configuration string for our Unit
move.l pndu_Number(a5),d0
bsr getconfigstr
move.b #PNDERR_UNIT_NOT_DEFINED,IO_ERROR(a3)
move.l d0,pndu_ConfigString(a5)
beq.s .noconf
* Load and start the driver
move.b #PNDERR_DRIVERTROUBLE,IO_ERROR(a3)
bsr StartDriver
tst.l d0
bne.s .nodriver
* Everything went O.K. -> Push back the startup packet and start working!
clr.b IO_ERROR(a3)
move.l a3,a1
LIBCALL ReplyMsg
clr.w pndu_RC(a5)
bsr MainLoop
bsr StopDriver
.nodriver move.l pndu_ConfigString(a5),a0
bsr freeconfigstr
.noconf move.l pndu_MsgPort(a5),a0
bsr DeletePort
.noport2 move.l pndu_MsgBackPort(a5),a0
bsr DeletePort
.noport move.l pndu_DOSBase(a5),a1
move.l 4.w,a6
LIBCALL CloseLibrary
.nodos tst.w pndu_RC(a5)
beq.s .returnfinal
LIBCALL Forbid ;Use Forbid() to prevent Exec from a task change
move.l a3,a1 ;between ReplyMsg and the complete discard of the
LIBJMP ReplyMsg ;process!
.returnfinal LIBCALL Forbid
move.l expungetask(pc),a1
moveq #0,d0
move.b expungesignal(pc),d1
bset d1,d0
LIBJMP Signal
* These routines handle the configuration file:
; -- Obtain configuration string
getconfigstr ; d0 number (0..n)
; a5 *pndu
; RETURNS d0 *line-string or NULL if it doesn't exist
movem.l d2-d7/a2-a6,-(sp)
move.l d0,a2
moveq #0,d4 ;[d4] RC
* Read Config File
move.l pndu_DOSBase(a5),a6
move.l #configname,d1
move.l #MODE_OLDFILE,d2
LIBCALL Open
move.l d0,d7
beq .nofile
move.l d7,d1
moveq #0,d2
move.l #OFFSET_END,d3
LIBCALL Seek
move.l d7,d1
moveq #0,d2
move.l #OFFSET_BEGINNING,d3
LIBCALL Seek
addq.l #1,d0
move.l d0,d5 ;[d5] configmemsize
move.l #MEMF_CLEAR,d1
move.l pndu_SysBase(a5),a6
LIBCALL AllocMem
tst.l d0
beq .nomem
move.l d0,a3 ;[a3] configmem
move.l d0,a4
move.l d7,d1
move.l a3,d2
move.l d5,d3
subq.l #1,d3
move.l pndu_DOSBase(a5),a6
LIBCALL Read
cmp.l d0,d3
bne.s .readerr
* Now search the line ID
move.l a2,d2
.loop subq.w #1,d2
bcc.s .next
* Get string length
move.l a3,a0
.getlen move.b (a0)+,d0
cmp.b #32,d0
bcc.s .getlen
sub.l a3,a0
move.l a0,d0
subq.l #1,d0
beq.s .readerr
* Copy string
move.w d0,d2
addq.l #5,d0 ;EOS + Length Tracking
move.l d0,d3
move.l pndu_SysBase(a5),a6
moveq #MEMF_PUBLIC,d1
LIBCALL AllocMem
tst.l d0
beq.s .readerr
move.l d0,a0
move.l d3,(a0)+
move.l a0,d4
subq.w #1,d2
.copy move.b (a3)+,(a0)+
dbra d2,.copy
clr.b (a0)+
bra.s .readerr
* Jump to next line
.next move.b (a3)+,d0
beq.s .readerr
cmp.b #10,d0
beq.s .loop
bra.s .next
.readerr move.l a4,a1
move.l d5,d0
move.l pndu_SysBase(a5),a6
LIBCALL FreeMem
.nomem move.l d7,d1
move.l pndu_DOSBase(a5),a6
LIBCALL Close
.nofile move.l d4,d0
.ende movem.l (sp)+,d2-d7/a2-a6
rts
; -- Dispose configuration string
freeconfigstr ; a0 *line-string got by 'getconfigstr'
move.l a6,-(sp)
move.l -(a0),d0
move.l a0,a1
move.l pndu_SysBase(a5),a6
LIBCALL FreeMem
move.l (sp)+,a6
rts
; -- Load the interface driver and initialize it.
StartDriver ; RETURNS d0 <>NULL on failure!
movem.l a2/a6,-(sp)
lea pndu_DriverName(a5),a1
lea driverpath(pc),a0
.l0 move.b (a0)+,(a1)+
bne.s .l0
subq.l #1,a1
move.l a1,a2
move.l pndu_ConfigString(a5),a0
.l1 move.b (a0)+,d0
move.b d0,(a1)+
cmp.b #" ",d0
bhi.s .l1
clr.b -(a1)
move.l a0,d6
move.l pndu_DOSBase(a5),a6
lea pndu_DriverName(a5),a1
move.l a1,d1
LIBCALL LoadSeg
move.l d0,pndu_DriverSeg(a5) ;(a5) was missing in V2 & V3 -> Enforcer hit!
bne.s .c1
move.l #mc_err3,d0
bra.s .0000
.c1 add.l d0,d0
add.l d0,d0
addq.l #4,d0
move.l d0,a2
* And now, Ladies & Gentlemen :))
lea pndu_DriverData(a5),a0
move.l d6,a1 ;ConfString after Driver-ID
move.l #"RST!",d0
moveq #2,d1 ;ProNET >V3
jsr (a2)
tst.l d0
beq.s .ende
* Copy the extensive error message when requested.
.0000 btst #PNB_ERRORSTRING,pnr_Length+3(a3)
beq.s .error2
cmp.l #PNDRVERR_NO_MEMORY,d0
bne.s .000
move.l #mc_err1,d0
.000 cmp.l #PNDRVERR_WRONG_ARGS,d0
bne.s .001
move.l #mc_err2,d0
.001 move.l d0,a0
move.l pnr_Data(a3),a1
moveq #62,d0
.00cpy move.b (a0)+,(a1)+
dbeq d0,.00cpy
clr.b (a1)+
.error2 move.l pndu_DOSBase(a5),a6
move.l pndu_DriverSeg(a5),d1
beq.s .error
LIBCALL UnLoadSeg
.error moveq #-1,d0
.ende movem.l (sp)+,a2/a6
rts
; -- Cancel the interface driver
StopDriver move.l pndu_DriverData+pndd_Exit(a5),a0
jsr (a0)
move.l pndu_DOSBase(a5),a6
move.l pndu_DriverSeg(a5),d1
LIBCALL UnLoadSeg
rts
******************
; -- The Main Loop
******************
MainLoop
move.l pndu_MsgBackPort(a5),a0
move.b MP_SIGBIT(a0),d2
move.b pndu_DriverData+pndd_ReadSignalBit(a5),d3
move.l pndu_MsgPort(a5),a0
move.b MP_SIGBIT(a0),d4
moveq #0,d5
bset #SIGBREAKB_CTRL_C,d5
bset d2,d5
bset d3,d5
bset d4,d5 ;[d5] Signalmask to wait for
movem.l a6/d2-d5,-(sp)
Wait4Msg movem.l (sp),a6/d2-d5
bsr CheckWrites
move.l d5,d0
LIBCALL Wait
btst #SIGBREAKB_CTRL_C,d0
bne.s StopThisShit
movem.l d0/d3/d4,-(sp)
btst d2,d0
bne MessageBack
wait1 movem.l (sp),d0/d3/d4
btst d3,d0
bne ReceiveData
wait2 movem.l (sp)+,d0/d3/d4
btst d4,d0
bne MessageLoop
bra Wait4Msg
StopThisShit movem.l (sp)+,a6/d2-d5
rts
; -- Look at the history, 31-05-95 for reasons why we do this!
CheckWrites
lea pndu_PendingWrites(a5),a0
TSTLIST a0
beq.s .okay
move.b pndu_DriverData+pndd_ReadSignalBit(a5),d0
moveq #0,d1
bset d0,d1
moveq #-1,d0
LIBCALL SetSignal
.okay rts
*****i* pronet.device/ReceiveData *******************************************
*
* NAME
* ReceiveData -- read incoming data from driver.
*
*****************************************************************************
*
*
******* pronet.device/ReceivedData ******************************************
*
* Received data will be sent to the MsgPort you specified in pnr_MsgPort
* when opening the device. You can not change it after opening.
* mn_Length, as opposed to pre-v37, contains the length of the whole Message
* structure. The first word of mn_Node.ln_Name contains the source ProNET
* Port, the second word contains the destination port. The data comes behind
* the Message structure.
*
* This Message must be replied as soon as there is no use for it any more.
*
* If there is incoming data but pronet.device can't allocate the Message
* structure, the packet is lost!
*
*****************************************************************************
*
*
ReceiveData
move.l pndu_DriverData+pndd_ReadQuery(a5),a0 ;Do external driver magic..
jsr (a0)
* d0.w length (if NULL then exit!!!)
* d1 destination port
* d2 source port
ext.l d0
beq .ende
move.w d1,d7
move.w d2,d5
add.l #MN_SIZE,d0
move.l d0,d6
.tryagain moveq #MEMF_PUBLIC,d1
LIBCALL AllocMem
tst.l d0
bne.s .memok
* No memory! Forget it! (ProNET <=V3 would busy wait until
* memory is free. This was BAD!)
move.l pndu_DriverData+pndd_ReadFlush(a5),a0
jsr (a0)
bra.s .ende
* Now get the data and build a Message
.memok move.l d0,a3
lea MN_SIZE(a3),a0
move.l pndu_DriverData+pndd_Read(a5),a1
jsr (a1)
move.w d5,LN_NAME(a3)
move.w d7,LN_NAME+2(a3)
move.w d6,MN_LENGTH(a3)
move.l pndu_MsgBackPort(a5),MN_REPLYPORT(a3)
move.b #NT_MESSAGE,LN_TYPE(a3)
lea pndu_PendingReads(a5),a0
move.l a3,a1
LIBCALL AddTail
.ende bsr TryPendingReads
bsr TryPendingWrites
bra wait2
*****i* pronet.device/MessageLoop *******************************************
*
* NAME
* MessageLoop -- process applications' commands.
*
* FUNCTION
* We got a new request from one of our clients.. well we could say we
* are currently busy but then he would use ParNet ;-)
*
*****************************************************************************
*
*
MessageLoop
move.l pndu_MsgPort(a5),a0
LIBCALL GetMsg
tst.l d0
beq Wait4Msg ;no more messages
move.l d0,a2
move.w IO_COMMAND(a2),d0
cmp.w #CMD_WRITE,d0
beq CMD__WRITE
cmp.w #PNDCMD_ADDPORT,d0
beq CMD__ADDPORT
cmp.w #PNDCMD_REMPORT,d0
beq CMD__REMPORT
move.b #IOERR_NOCMD,IO_ERROR(a2)
move.l a2,a1
LIBCALL ReplyMsg
bra MessageLoop
*****i* pronet.device/CMD_ADDPORT *******************************************
*
* NAME
* AddPort -- New device opener.
*
*****************************************************************************
*
*
CMD__ADDPORT
move.w pnr_NetSourcePort(a2),d1
cmp.w #PNP_NEXTFREE,d1
bne.s .0
moveq #1,d1
lea pndu_PortList(a5),a1
.next move.l a1,a0
.loop1 move.l (a0),d0
beq.s .notfound
move.l d0,a0
cmp.w pndp_Number(a0),d1
bne.s .loop1
addq.w #1,d1
bra.s .next
.notfound move.w d1,pnr_NetSourcePort(a2)
.0 move.b #IOERR_OPENFAIL,IO_ERROR(a2)
* See if port already exists, portnumber in d1 now
lea pndu_PortList(a5),a0
.loop0 move.l (a0),d0
beq.s .ok
move.l d0,a0
cmp.w pndp_Number(a0),d1
bne.s .loop0
* Sorry
move.b #PNDERR_PORTEXISTS,IO_ERROR(a2)
bra.s .ende
* No, add it!
.ok moveq #pndp_SizeOf,d0
moveq #0,d1
LIBCALL AllocMem
tst.l d0
beq.s .ende
move.l d0,a4
move.w pnr_NetSourcePort(a2),pndp_Number(a4)
move.l pnr_MsgPort(a2),pndp_MsgPort(a4)
lea pndu_PortList(a5),a0
move.l (a0),(a4)
move.l a4,(a0)
bsr TryPendingReads
clr.b IO_ERROR(a2) ;Okay, port added
.ende move.l a2,a1
LIBCALL ReplyMsg
bra MessageLoop
*****i* pronet.device/CMD_REMPORT *******************************************
*
* NAME
* RemPort -- Device is closed.
*
*****************************************************************************
*
*
CMD__REMPORT
move.w pnr_NetSourcePort(a2),d2
lea pndu_PortList(a5),a1
.find move.l a1,a3
move.l (a1),d0
beq.s .notfound
move.l d0,a1
cmp.w pndp_Number(a1),d2
bne.s .find
move.l (a1),d2
moveq #pndp_SizeOf,d0
LIBCALL FreeMem
move.l d2,(a3) ;Teil aus der Liste entfernt !!
move.l a2,a1
LIBCALL ReplyMsg
.notfound bra MessageLoop
******* pronet.device/CMD_WRITE *********************************************
*
* NAME
* Write -- send output to ProNET Port.
*
* FUNCTION
* This command causes a packet of data to be written out the ProNET
* Port/Unit. The number of characters is specified in pnr_Length.
*
* IO REQUEST
* io_Command - CMD_WRITE
* pnr_Data - pointer to block of data to transmit
* pnr_Length - number of characters to transmit. MUST BE EVEN AND MUST
* NOT BE GREATER THAN 0x4000!
*
* RESULTS
* io_Error - if the Write succeeded, then io_Error will be zero.
* The only other possible error code is PNDERR_DESTINATION_GONE.
*
*****************************************************************************
*
*
CMD__WRITE
move.l a2,a1
lea pndu_PendingWrites(a5),a0
LIBCALL AddTail
bsr TryPendingWrites
bra MessageLoop ;kurz und schmerzlos :-)
*****i* pronet.device/MessageBack *******************************************
*
* NAME
* MessageBack -- Application replied a ProNET Message.
*
* FUNCTION
* Free the message structure and data.
*
*****************************************************************************
*
*
MessageBack
move.l pndu_MsgBackPort(a5),a0
LIBCALL GetMsg
tst.l d0
beq wait1
move.l d0,a1
moveq #0,d0
move.w MN_LENGTH(a1),d0
LIBCALL FreeMem
bra.s MessageBack
*****i* pronet.device/TryPendingReads *******************************************
*
* NAME
* TryPendingReads -- Iterate through this Unit's pending reads list.
*
* FUNCTION
* ProNET remembers all messages for ports that are not currently open
* and sends them off when they are opened.
*
*****************************************************************************
*
*
TryPendingReads
move.l a2,-(sp)
lea pndu_PendingReads(a5),a3
move.l LH_HEAD(a3),a2
addq.l #4,a3
.looop cmp.l a2,a3
bne.s .doit
move.l (sp)+,a2
rts
.doit move.l a2,a4
move.l LN_SUCC(a2),a2
move.w LN_NAME+2(a4),d1
lea pndu_PortList(a5),a0
.find move.l (a0),d0
beq.s .looop
move.l d0,a0
cmp.w pndp_Number(a0),d1
bne.s .find
move.l pndp_MsgPort(a0),d5
move.l a4,a1
LIBCALL Remove
move.l d5,a0
move.l a4,a1
LIBCALL PutMsg
bra.s .looop
*****i* pronet.device/TryPendingWrites **************************************
*
* NAME
* TryPendingWrites -- Process pending write requests.
*
* FUNCTION
* This routine checks this Unit on unprocessed write requests and
* sends them off if possible.
*
*****************************************************************************
*
*
TryPendingWrites
move.l a2,-(sp)
lea pndu_PendingWrites(a5),a3
move.l LH_HEAD(a3),a2
addq.l #4,a3
.looop cmp.l a2,a3
bne.s .doit
.busy move.l (sp)+,a2
rts
.doit move.l a2,a4
move.l LN_SUCC(a2),a2
.noxpk move.l pnr_Data(a4),a0
move.l pnr_Length(a4),d0
addq.l #1,d0 ;round up to word boundary
bclr #0,d0
move.w pnr_NetDestPort(a4),d1
move.w pnr_NetSourcePort(a4),d2
move.l pndu_DriverData+pndd_Write(a5),a6
jsr (a6) ;Send the data
move.l pndu_SysBase(a5),a6
tst.w d0
beq.s .okay
bmi.s .busy
* Remote machine doesn't respond, reply CMD_WRITE with
* an error.
move.l a4,a1
LIBCALL Remove
move.b #PNDERR_DESTINATION_GONE,IO_ERROR(a4)
bra.s .reply
.okay * IORequest done, reply it!
move.l a4,a1
LIBCALL Remove
clr.b IO_ERROR(a4)
.reply move.l a4,a1
LIBCALL ReplyMsg
bra .looop
** -----------------------------------------------------------------------
**
**
**
**
**
** Useful routines
**
**
**
**
**
** -----------------------------------------------------------------------
_mysprintf movem.l a2/a3/a6,-(sp)
move.l 4*4(sp),a3 ;Get the output string pointer
move.l 5*4(sp),a0 ;Get the FormatString pointer
lea 6*4(sp),a1 ;Get the pointer to the DataStream
lea .stuffChar(pc),a2
move.l 4.w,a6
LIBCALL RawDoFmt
movem.l (sp)+,a2/a3/a6
rts
.stuffChar move.b d0,(a3)+ ;Put data to output string
rts
include "P:include/devio_ports.s"
dosname dc.b "dos.library",0
configname dc.b "DEVS:ProNET/.config",0
FormatString dc.b "pronet.device (%ld)",0
driverpath dc.b "DEVS:ProNET/",0
mc_err1 dc.b "Out of memory.",0
mc_err2 dc.b "Wrong arguments in configuration file.",0
mc_err3 dc.b "Can't find specified driver module.",0
even
EndResident: